import { ChangeDetectionStrategy, Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { cloneDeep, filter, uniqueId } from 'lodash';
import { Observable, Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators';
import { DatatableComponent, FilterItem, MessageboxService, PaginatorComponent, TagItem } from '@iux/live';

interface User {
  id: string;
  name: string;
  age: number;
  color: string;
  address: string;
  random: number;
}

@Component({
  selector: 'app-filter',
  templateUrl: './filter.component.html',
  styles: [
    `
      /*顶部搜索、按钮*/
      .demo-table-filter-top-content {
        display: flex;
        align-items: center;
        margin-bottom: 16px;
      }
      .demo-table-filter-top-content .demo-table-filter-search {
        width: 272px;
      }
      .demo-table-filter-top-content button {
        margin-left: 16px;
      }
      .demo-table-filter-tag-content {
        margin-bottom: 16px;
      }
      /*分页器*/
      lv-paginator {
        margin-top: 16px;
      }
    `,
  ],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class FilterComponent implements OnInit, OnDestroy {
  listenSearch = true;

  filterTags: TagItem[] = [];

  data: User[] = [];
  activeSort;

  filtersMap: { [key: string]: any } = {};
  cacheFiltersMap: { [key: string]: any } = {};
  filterState: FilterItem[] = [];

  value;

  search$ = new Subject<string>();
  destroy$ = new Subject<void>();

  @ViewChild(DatatableComponent) lvTable: DatatableComponent;
  @ViewChild(PaginatorComponent) lvPage: PaginatorComponent;

  constructor(private messageBox: MessageboxService) {}

  ngOnInit(): void {
    this.initData();
    this.searchSubscribe();
    this.setFilters();
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }

  initData() {
    this.data = Array.from({ length: 30 }).map((item, key) => this.initUser(key));
  }

  initUser(key: number): User {
    const colors = ['red', 'blue', 'green', 'orange'];
    const random = parseInt(`${Math.random() * 100}`, 10);

    return {
      id: uniqueId('uid'),
      name: `User${key}`,
      age: 10 + key,
      color: colors[random % colors.length],
      address: `Address ${key} Park Road, Sichuan`,
      random,
    };
  }

  setFilters() {
    const ageFilters = [
      { key: 0, label: '10', value: '10' },
      { key: 1, label: '15', value: '15' },
      { key: 2, label: '20', value: '20' },
      { key: 3, label: '25', value: '25' },
      { key: 4, label: '30', value: '30' },
    ];
    const colorFilters = [
      { key: 0, label: 'Red', value: 'red' },
      { key: 1, label: 'Blue', value: 'blue' },
      { key: 2, label: 'Green', value: 'green' },
    ];
    const randomFilters = [
      { key: 0, label: 'odd', value: false },
      { key: 1, label: 'even', value: true },
    ];

    this.filtersMap.name = '';
    this.filtersMap.age = ageFilters;
    this.filtersMap.color = colorFilters;
    this.filtersMap.random = randomFilters;
    this.cacheFiltersMap = cloneDeep(this.filtersMap);
  }

  stateChange(source: any) {
    this.filterState = filter(source.filterState, item => item.value && item.value.length);
    this.filterTags = this.filterState.map((item: TagItem) => ({ label: item, removable: true }));
    console.log('table state update:', source);
  }

  updateSearch(e: any) {
    this.search$.next(e?.target?.value || '');
  }

  searchSubscribe(): void {
    this.search$.pipe(debounceTime(300), distinctUntilChanged(), takeUntil(this.destroy$)).subscribe(value => {
      if (this.listenSearch) {
        this.filterByName(value);
      }
    });
  }

  filterByName(value: string) {
    this.lvTable.filter({ key: 'name', value, filterMode: 'contains' });
    this.lvPage.jumpToFisrtPage();
  }

  toggleListenSearch(listenStatus: boolean, value?: string) {
    this.listenSearch = listenStatus;
    if (!listenStatus) {
      return this.lvTable.removeFilter('name');
    }
  }

  filterChange(options: any) {
    const { key, value } = options;
    if (key === 'age' && value?.includes('all')) {
      this.removeFilterState({ label: { key } });
      return;
    }

    this.lvTable.filter(options);
    this.lvPage.jumpToFisrtPage();
  }

  customFilterRandom<T>(data: T[], filterOptions: any): T[] {
    const filterValue = filterOptions.value;
    return filter(data, item => filterValue.includes(item.random % 2 === 0) || !filterValue.length);
  }

  beforeRemove = () =>
    new Observable(observer => {
      this.messageBox.confirm({
        lvHeader: 'Delete',
        lvContent: 'Are you sure you want to delete?',
        lvAfterClose: () => {
          observer.next(false);
          observer.complete();
        },
        lvOk: () => {
          observer.next(true);
        },
      });
    });

  removeFilterState(source) {
    const { key } = source.label;
    this.lvTable.removeFilter(key);
    this.filtersMap[key] = cloneDeep(this.cacheFiltersMap[key]);
  }

  clearFilterState() {
    this.lvTable.removeFilter();
    this.lvPage.jumpToFisrtPage();
    this.setFilters();
  }

  changeSort(options: any) {
    this.lvTable.sort(options);
    this.lvPage.jumpToFisrtPage();
  }

  clearSort() {
    this.lvTable.removeSort();
    this.activeSort = null;
  }

  trackBy = (_, item: TagItem): string => item.label.key;
}
